namespace ts_class_1 {
  /**
   * 类的定义
   * 1. 基本定义：使用 class 关键字定义一个类。类可以包含属性、构造函数和方法。
   * 2. 参数属性： 使用参数属性，省去了单独声明和赋值的步骤，属性在构造函数中直接初始化
   * 3. 访问修饰符：
   *      - public: 默认修饰符，在任何地方都可以访问
   *      - private: 私有属性，只能在类的内部访问（建议私有属性名带下划线，规范书写）
   *      - protected: 受保护的属性，只能在类的内部及其子类中访问
   * 4. TS中存取器（Getters and Setters)：可以通过存取器访问及修改私有属性
   * 5. 静态成员：使用 static 关键字定义，只能通过类名调用，不能通过实例调用
   * 6. 只读属性：readonly 关键字用于定义只读属性，只能在初始化时或在构造函数中赋值，之后不能再修改。
   * 
   */

  // 1.1 基本定义
  class Person {
    // 属性与构造函数写法一：分开写
    // name: string
    // age: number

    // constructor(name: string, age: number){
    //   this.name = name
    //   this.age = age
    // }

    // 属性与构造函数写法二：声明与赋值合并
    constructor(public name: string, public age: number) { }
    greet() {
      console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
    }
  }

  const person = new Person('John', 25)
  person.greet()

  // 1.2 参数属性
  class Animal {
    constructor(private name: string) { }
    move(distanceInMeters: number) {
      console.log(this.name + " moved " + distanceInMeters + " meters.");
    }
  }
  const animal = new Animal('Lion')
  animal.move(34)

  // 1.3 访问修饰符
  class Employee {
    // public name: string
    // private salary: number
    // protected department: string

    // constructor(name: string, salary: number, department: string){
    //   this.name = name
    //   this.salary = salary
    //   this.department = department
    // }
    constructor(
      public name: string,
      private _salary: number,
      protected department: string
    ) { }

    getSalary() {
      return this._salary    //私有属性只能在类的内部访问
    }

    getDepartment() {
      return this.department    //受保护的属性只能在类的内部及其子类中访问
    }
  }
  const employee = new Employee('Jack', 50000, 'Engineering')
  console.log(employee.name);  //输出：Jack
  // console.log(employee.salary);  //报错：属性“salary”为私有属性，只能在类“Employee”中访问
  // console.log(employee.department); //报错：属性“department”受保护属性，只能在类“Employee”及其子类中访问
  console.log(employee.getSalary());  //输出：50000
  console.log(employee.getDepartment());  //输出：Engineering

  // 1.4 TS中存取器（Getters and Setters)
  class Animal1 {
    private _age: number = 0

    constructor(public name: string) { }

    get age(): number {
      console.log(`获取${this.name}的年龄`);
      return this._age    //可以通过存取器访问私有属性
    }
    // get age(): string {
    //   return `获取${this.name}的年龄:${this._age}`  
    // }

    set age(value: number) {
      if (value < 0) {
        console.log(`年龄不能为负数`);
      } else {
        console.log(`设置${this.name}的年龄为${value}`);
        this._age = value  //可以通过存取器修改私有属性
      }
    }

    printInfo(): void {
      console.log(`我是${this.name}, 今年${this._age}岁了`);
    }
  }

  const animal1 = new Animal1('小猫');
  animal1.age = 2
  console.log(animal1.age);  //输出：获取小猫的年龄:2
  animal1.printInfo();  //输出：我是小猫, 今年2岁了
  animal1.age = -1;  //输出：年龄不能为负数
  animal1.age = 3;  //输出：设置小猫的年龄为3

  // 1.5 静态成员
  class MathUtils {
    static PI: number = 3.141592653589793
    static calculateArea(radius: number): number {
      return this.PI * radius * radius
    }
  }
  // 访问静态属性
  console.log(MathUtils.PI);  //输出：3.141592653589793
  const math = new MathUtils()
  // console.log(math.PI);  //报错：属性“PI”在类型“MathUtils”上不存在。你的意思是改为访问静态成员“MathUtils.PI”吗?
  console.log(MathUtils.calculateArea(2));  //输出：12.566370614359172F

  // 1.6 只读属性
  class Car {
    // readonly brand: string
    // readonly model: string

    // constructor(brand: string, model: string) {
    //   this.brand = brand
    //   this.model = model
    // }
    constructor(
      readonly brand: string, 
      readonly model: string
    ) {}
  }

  const car = new Car('BMW', 'X5')
  // car.brand = 'Audi'  //报错：不能将类型“string”分配给类型“readonly string”。
  // car.model = 'A8'  //报错：不能将类型“string”分配给类型“readonly string”。
  console.log(car.brand);  //输出：BMW

}

